[TRTLLM-14715][feat] preserve native MoE A2A graph VAs across restore - #16632
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughMNNVL memory now supports bounded checkpoint detachment and restoration with lifecycle tracking and cleanup. Shared MoE workspaces coordinate mapped state, watchdogs, and checkpoint operations. Executor sleep-wakeup flows coordinate these hooks across ranks and handle partial failures. ChangesMNNVL checkpoint lifecycle
Estimated code review effort: 4 (Complex) | ~60 minutes Merge Risk: 🟠 High · up to This PR changes checkpoint/restore and distributed sleep/wakeup handling for native MoE communication resources. The current head still contains failure-path and resource-lifecycle issues that can unnecessarily stop workers, disturb shared distributed state, or retain stale mappings across restore, with an additional test-flakiness concern. The correctness issues should be fixed or explicitly accepted by the owners before merge. Sequence Diagram(s)sequenceDiagram
participant BaseWorker
participant PyExecutor
participant WorkspaceLifecycle
participant MnnvlMemory
participant Communicator
BaseWorker->>PyExecutor: PREPARE sleep or wakeup
PyExecutor->>WorkspaceLifecycle: detect MNNVL resources
BaseWorker->>Communicator: send peer COMMIT
PyExecutor->>WorkspaceLifecycle: checkpoint_prepare()
WorkspaceLifecycle->>MnnvlMemory: detach workspace handles
BaseWorker->>PyExecutor: release or materialize VMM memory
PyExecutor->>WorkspaceLifecycle: checkpoint_restore(comm)
WorkspaceLifecycle->>MnnvlMemory: remap workspace handles
WorkspaceLifecycle->>Communicator: validate restore readiness
WorkspaceLifecycle-->>PyExecutor: reset communication state
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tensorrt_llm/_torch/modules/fused_moe/communication/nvlink_one_sided.py (1)
703-722: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider mirroring the
_require_mapped()guard here for cross-implementation consistency.
MoeAlltoAll.get_combine_payload_tensor_in_workspace()callsself._require_mapped()before the phase check, but this NVLink one-sided variant does not. In practice thephase != "dispatched"guard already blocks reaching this while handles are detached (checkpointing requires theidlephase), so this is a defense-in-depth consistency nit rather than a live bug. Aligning both keeps the two frontends symmetric if the phase semantics ever change.♻️ Optional consistency tweak
def get_combine_payload_tensor_in_workspace( self, runtime_max_tokens_per_rank: int, hidden_size: int, dtype: torch.dtype ) -> torch.Tensor: ... + self._require_mapped() if self._dispatch_state.get("phase") != "dispatched": raise RuntimeError( "get_combine_payload_tensor_in_workspace called before a successful dispatch" )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tensorrt_llm/_torch/modules/fused_moe/communication/nvlink_one_sided.py` around lines 703 - 722, Update get_combine_payload_tensor_in_workspace to call the existing _require_mapped() guard before checking the dispatch phase, matching MoeAlltoAll’s implementation while preserving the current phase validation and behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@tensorrt_llm/_torch/modules/fused_moe/communication/nvlink_one_sided.py`:
- Around line 703-722: Update get_combine_payload_tensor_in_workspace to call
the existing _require_mapped() guard before checking the dispatch phase,
matching MoeAlltoAll’s implementation while preserving the current phase
validation and behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: bc5812ec-a3d9-4c6c-9695-5f1fa61aa472
📒 Files selected for processing (5)
tensorrt_llm/_mnnvl_utils.pytensorrt_llm/_torch/distributed/moe_alltoall.pytensorrt_llm/_torch/modules/fused_moe/communication/nvlink_one_sided.pytensorrt_llm/_torch/modules/fused_moe/communication/nvlink_two_sided.pytests/unittest/_torch/test_mnnvl_memory_lifecycle.py
chienchunhung
left a comment
There was a problem hiding this comment.
Thanks for working on this. I left two lifecycle questions inline.
|
@chienchunhung A lot of your requests are intentionally isolated in hhzhang16#1 so the shared lifecycle and failure-handling changes can be reviewed there first. Then I’ll merge them into #16632. |
brnguyen2
left a comment
There was a problem hiding this comment.
The VA-preservation design looks correct: metainfo is a CPU offsets tensor (CHECK_CPU in moeAlltoAllOp.cpp), so the equality-check-then-swap after restore is safe for captured graphs, and the new barrier before closing exported fds in the POSIX-fd path is the right fix for the fd lifetime (which the old code handled by leaking the fds).
A few things beyond the inline comments:
- No in-tree caller.
checkpoint_prepare/checkpoint_restoreare added but nothing invokes them. Please state in the description where the orchestration lands (follow-up PR? external framework?), and document thecommparameter contract on the public methods — it must be an mpi4py-like object withGet_rank/Get_size/barrier, matching the original allocation's rank and size, called symmetrically on every rank after all in-flight dispatch/combine pairs have completed. - Test Coverage section is empty. The new unit tests are mock-based and don't exercise the real collective detach/remap; please note whether a multi-GPU test (even a manual one) validated an actual unmap → remap → dispatch/combine → graph-replay cycle.
- The description doesn't mention the two-sided behavioral change (
combinenow clears_dispatch_state) — worth a sentence, see inline. MoeAlltoAll.checkpoint_restoreandNVLinkOneSided.checkpoint_restoreare ~30 near-identical lines. The files already carry a "can we avoid this duplication" TODO for_init_constants; consider a shared helper rather than growing the duplication.
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
tests/unittest/_torch/test_mnnvl_memory_lifecycle.py (1)
290-349: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd direct coverage for the new
MnnvlMoelifecycle statics.The tests cover
MnnvlMemoryand the two communication wrappers. They never call the realMnnvlMoe.checkpoint_prepare,MnnvlMoe.checkpoint_restore, orMnnvlMoe.require_mapped. Line 339 replacesrequire_mappedwith aMock, so its logic stays untested.Three branches in
tensorrt_llm/_mnnvl_utils.pylines 655-685 have no coverage: theNoneguard for each workspace, the conditionalmoe_initialize_workspacecall whenmoe_workspace_tensoris set, and the per-workspacemappedcheck. Monkeypatched workspace mocks are enough, matching the pattern at lines 302-304.💚 Suggested additional tests
def test_moe_require_mapped_rejects_detached_prepare_workspace(monkeypatch): monkeypatch.setattr(mnnvl.MnnvlMoe, "moe_workspace", Mock(mapped=True)) monkeypatch.setattr(mnnvl.MnnvlMoe, "moe_prepare_workspace", Mock(mapped=False)) with pytest.raises(RuntimeError, match="workspace handles are unmapped"): mnnvl.MnnvlMoe.require_mapped() def test_moe_checkpoint_prepare_skips_unallocated_workspaces(monkeypatch): workspace = Mock(mapped=True) monkeypatch.setattr(mnnvl.MnnvlMoe, "moe_workspace", workspace) monkeypatch.setattr(mnnvl.MnnvlMoe, "moe_prepare_workspace", None) mnnvl.MnnvlMoe.checkpoint_prepare() workspace.checkpoint_prepare.assert_called_once_with()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/unittest/_torch/test_mnnvl_memory_lifecycle.py` around lines 290 - 349, Add direct tests for MnnvlMoe.checkpoint_prepare, MnnvlMoe.checkpoint_restore, and MnnvlMoe.require_mapped using monkeypatched workspace objects. Cover None workspaces, conditional moe_initialize_workspace when moe_workspace_tensor is set, per-workspace mapped validation, and delegation to checkpoint methods; remove the require_mapped mock in test_two_sided_combine_requires_new_prepare_before_next_dispatch so the real logic is exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/unittest/_torch/modules/moe/test_moe_comm.py`:
- Around line 2562-2665: Wrap the main execution of
_worker_mnnvl_checkpoint_graph_replay in a try/finally block so
communication.destroy() always runs, including assertion and MPI worker
failures. Keep the existing conditional destroy operation in the finally block,
ensuring persistent worker state is reset before reuse.
---
Nitpick comments:
In `@tests/unittest/_torch/test_mnnvl_memory_lifecycle.py`:
- Around line 290-349: Add direct tests for MnnvlMoe.checkpoint_prepare,
MnnvlMoe.checkpoint_restore, and MnnvlMoe.require_mapped using monkeypatched
workspace objects. Cover None workspaces, conditional moe_initialize_workspace
when moe_workspace_tensor is set, per-workspace mapped validation, and
delegation to checkpoint methods; remove the require_mapped mock in
test_two_sided_combine_requires_new_prepare_before_next_dispatch so the real
logic is exercised.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 67f3bd11-420a-4d0a-8066-3f4df3d96857
📒 Files selected for processing (8)
tensorrt_llm/_mnnvl_utils.pytensorrt_llm/_torch/distributed/moe_alltoall.pytensorrt_llm/_torch/modules/fused_moe/communication/nvlink_one_sided.pytensorrt_llm/_torch/modules/fused_moe/communication/nvlink_two_sided.pytests/integration/test_lists/test-db/l0_a10.ymltests/integration/test_lists/test-db/l0_gb200_multi_gpus.ymltests/unittest/_torch/modules/moe/test_moe_comm.pytests/unittest/_torch/test_mnnvl_memory_lifecycle.py
🚧 Files skipped from review as they are similar to previous changes (3)
- tensorrt_llm/_torch/modules/fused_moe/communication/nvlink_one_sided.py
- tensorrt_llm/_torch/distributed/moe_alltoall.py
- tensorrt_llm/_torch/modules/fused_moe/communication/nvlink_two_sided.py
brnguyen2
left a comment
There was a problem hiding this comment.
Approving — the comments below are optional touch-ups, not blockers.
Two description notes:
- The new
checkpoint_prepare/checkpoint_restoresurface has no in-tree caller — it's staged infrastructure for an external fault-tolerance orchestrator (per the FlashInfer port). Please name the intended consumer/orchestration path in the description, and fill in the template's "Test Coverage" section (the CodeRabbit block lists the tests, but the template section is what release tooling and future readers scan). - An incidental behavior change worth a line in the description: the non-fabric path now closes pidfds, imported fds, and the exported fd on the success path (previously they leaked), which is why the new
comm.barrier()after thepidfd_getfdloop is required — peers must finish duplicating an exported fd before its owner closes it. Both look correct; just make it explicit that the barrier is intentional.
Everything from the earlier review rounds (guarded fd closes, restored EPERM/ENOSYS hints, the cls.comm intent comment, the dispatch-after-combine regression test) is verified addressed on the current head.
|
PR_Github #67963 [ run ] triggered by Bot. Commit: |
|
PR_Github #67963 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
1 similar comment
|
/bot run --disable-fail-fast |
|
PR_Github #68367 [ run ] triggered by Bot. Commit: |
|
PR_Github #68367 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #68408 [ run ] triggered by Bot. Commit: |
|
PR_Github #68408 [ run ] completed with state |
|
/bot run --disable-fail-fast |
|
PR_Github #68838 [ run ] triggered by Bot. Commit: |
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
94eeb20 to
711bad5
Compare
|
/bot run --disable-fail-fast |
|
PR_Github #68887 [ run ] triggered by Bot. Commit: |
|
PR_Github #68838 [ run ] completed with state |
|
PR_Github #68887 [ run ] completed with state
|
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Summary
Dev Engineer Review
L0_MergeRequest_PRpipelines failed. Failed tests require review and a new CI run.QA Engineer Review
tests/unittest/_torch/test_mnnvl_memory_lifecycle.py.tests/unittest/_torch/test_mnnvl_alltoall_workspace.py.TestMoEComm.test_communication_factory.py.test_sleep_collective_rpc_guards.py.tests/integration/test_lists/test-db/l0_a10.yml.tests/integration/test_lists/test-db/l0_gb200_multi_gpus.yml.tests/integration/test_lists/test-db/l0_cpu.yml.Description
This change ports the FlashInfer stable-VA lifecycle to TensorRT-LLM's native MoE all-to-all resources. FlashInfer implemented this lifecycle for its TRT-LLM-style MoE all-to-all workspace in flashinfer-ai/flashinfer#3727.
Test Coverage
PR Checklist
Please review the following before submitting your PR:
PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.
PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.
Test cases are provided for new code paths (see test instructions)
If PR introduces API changes, an appropriate PR label is added - either
api-compatibleorapi-breaking. Forapi-breaking, includeBREAKINGin the PR title.Any new dependencies have been scanned for license and vulnerabilities
CODEOWNERS updated if ownership changes
Documentation updated as needed
Update tava architecture diagram if there is a significant design change in PR.
The reviewers assigned automatically/manually are appropriate for the PR.
Please check this after reviewing the above items as appropriate for this PR.
GitHub Bot Help
To see a list of available CI bot commands, please comment
/bot help.